﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.ComponentModel;
using Sinacor.Infra.Service.Validation;
using Sinacor.Infra.Service.Common;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using Sinacor.Infra.Service.Security.Authorization;



namespace Sinacor.Servico.Bovespa.ManutencaoOrdens.BusinessLogic
{
    public class Casamento : BaseBusinessLogic
    {

        #region Construtores
        private ResourceAccess.Casamento _casamento;
        public Casamento()
            : base()
        {
            _casamento = new Sinacor.Servico.Bovespa.ManutencaoOrdens.ResourceAccess.Casamento();
        }
        #endregion Construtores

        #region Constantes Erro
        private int ERRO_OBJETO_NULO = 109381;
        private int ERRO_MOVIMENTO_DIFERENTE_ABERTO = 109509;
        private int ERRO_USUARIO_SEM_PREMISSAO_ACESSO = 109507;
        private int ERRO_ORDEM_INESISTENTE = 109426;
        private int ERRO_ORDEM_NAOPERMITE_CASAMENTO = 109553;
        private int ERRO_CASAMENTOORDEM = 109548;
        private int ERRO_ORDEMDISTRIBUIDA = 109550;
        private int ERRO_ORDEMABERTA_EXERCICIO = 109551;
        private int ERRO_DESCASARORDEM = 109552;
        private int ERRO_QUANTIDADE_MAIORSALDO = 109577;
        private int ERRO_OBJETO_CASAMENTO_NULO = 109489;
        private int ERRO_NAO_PERMITE_CASAMENTO = 109508;
        private int ERRO_CASAR_PREBOLETO = 109513;


        #endregion

        /// <summary>
        /// Realiza o casamento de um negócio e uma ordem
        /// </summary>
        /// <param name="entity"></param>
        private void CasarNegocio(BusinessEntity.Negocio entity)
        {
            BusinessEntity.Resultado resultado = null;
            resultado = _casamento.CasarNegocio(entity);

            if (resultado.Sucesso == false)
                throw new BusinessException(ERRO_CASAMENTOORDEM);
        }

        /// <summary>
        /// Realiza o casamento dos negócios e ordens passados como parâmetro
        /// </summary>
        /// <param name="entityList"></param>
        public void CasarNegocios(BusinessEntity.ChaveOrdem entity, List<BusinessEntity.Negocio> entityList)
        {
            BusinessEntity.Ordem ordem = null;
            BusinessLogic.ManutencaoOrdens manutencao = null;
            decimal? somaSaldo;
            Parametro.BusinessLogic.Parametro businessParametro;
            bool calculoFinanceiro;

            if (entityList == null 
                || entity == null)
                throw new BusinessException(ERRO_OBJETO_NULO);

            this.ValidarEstadoMovimento();
            this.VerificarPermissaoAcesso();

            manutencao = new ManutencaoOrdens();
            ordem = manutencao.ObterOrdem(entity);

            if (ordem == null)
                throw new BusinessException(ERRO_ORDEM_INESISTENTE);

            if (!ordem.IndicadorCasaOrdem.HasValue
                || !ordem.IndicadorCasaOrdem.Value)
                throw new BusinessException(ERRO_ORDEM_NAOPERMITE_CASAMENTO);

            if (entityList.Count > 1)
            {
                somaSaldo = entityList.Sum(x => x.Saldo);

                if (somaSaldo.HasValue
                    && somaSaldo.Value > ordem.Saldo)
                    throw new BusinessException(ERRO_QUANTIDADE_MAIORSALDO);
            }

            businessParametro = new Parametro.BusinessLogic.Parametro();
            calculoFinanceiro = businessParametro.ObterParametro().CalculoAutomaticoFinanceiro;

            try
            {
                foreach (BusinessEntity.Negocio item in entityList)
                {
                    this.CasarNegocio(item);
                }

                if(calculoFinanceiro)
                    manutencao.CalcularFinanceiro();
            }
            catch (Exception)
            {
                if (calculoFinanceiro)
                    manutencao.CalcularFinanceiro();
                throw;
            }

        }

        /// <summary>
        /// Descasa de um negócio e uma ordem
        /// </summary>
        /// <param name="entity"></param>
        private void DescasarNegocio(BusinessEntity.Negocio entity)
        {

            //Chamar o método BusinessLogic.ManutencaoOrdens.ObterOrdem(), passando negocio.Ordem como parâmetro de entrada
            BusinessEntity.Ordem response = null;
            BusinessLogic.ManutencaoOrdens manutencao = new ManutencaoOrdens();
            response = manutencao.ObterOrdem(entity.Ordem);

            if (response == null)
                throw new BusinessException(ERRO_ORDEM_INESISTENTE);

            if (response.Distribuida == true)
                throw new BusinessException(ERRO_ORDEMDISTRIBUIDA);

            if (response.Situacao == BusinessEntity.Enum.SituacaoOrdem.Exercicio)
                throw new BusinessException(ERRO_ORDEMABERTA_EXERCICIO);

            if (!response.IndicadorCasaOrdem == true)
                throw new BusinessException(ERRO_ORDEM_NAOPERMITE_CASAMENTO);

            //Chamar o método ResourceAccess.Casamento.DescasarNegocio()
            BusinessEntity.Resultado resultado = null;
            resultado = _casamento.DescasarNegocio(entity);

            if (resultado.Sucesso == false)
                throw new BusinessException(ERRO_DESCASARORDEM);

        }

        /// <summary>
        /// Descasa os negócios e ordens passados como parâmetro
        /// </summary>
        /// <param name="entityList"></param>
        public void DescasarNegocios(List<BusinessEntity.Negocio> entityList)
        {
            Parametro.BusinessLogic.Parametro businessParametro;
            bool calculoFinanceiro;

            //Verificar o diagrama de atividade
            //Casamento.DescasarNegocios()

            if (entityList == null)
                throw new BusinessException(ERRO_OBJETO_NULO);

            this.ValidarEstadoMovimento();
            this.VerificarPermissaoAcesso();

            businessParametro = new Parametro.BusinessLogic.Parametro();
            calculoFinanceiro = businessParametro.ObterParametro().CalculoAutomaticoFinanceiro;

            try
            {
                foreach (BusinessEntity.Negocio item in entityList)
                {
                    this.DescasarNegocio(item);
                }

                if (calculoFinanceiro)
                {
                    BusinessLogic.ManutencaoOrdens manutencao = new ManutencaoOrdens();
                    manutencao.CalcularFinanceiro();
                }
            }
            catch (Exception)
            {
                if (calculoFinanceiro)
                {
                    BusinessLogic.ManutencaoOrdens manutencao = new ManutencaoOrdens();
                    manutencao.CalcularFinanceiro();
                    throw;
                }
            }

        }

        /// <summary>
        /// Realiza o tratamento de exceções geradas em chamadas de função ou procedure
        /// </summary>
        /// <param name="resultado"></param>
        private void TratarExcecoes(BusinessEntity.Resultado resultado)
        {

            if (string.IsNullOrEmpty(resultado.Argumentos))
                throw new BusinessException(resultado.CodigoErro);
            else
            {
                List<Object> _params = ErrorMessage.ConvertXmlArgumentsToParameters(resultado.Argumentos);

                if (_params != null)
                    throw new BusinessException(resultado.CodigoErro, _params.ToArray());
                else
                    throw new BusinessException(resultado.CodigoErro);

            }

        }


        /// <summary>
        /// Verifica se o movimento de ordens se encontra aberto
        /// </summary>
        /// <param name="entityList"></param>
        private void ValidarEstadoMovimento()
        {
            Sinacor.Servico.Bovespa.Movimento.BusinessEntity.InformacoesMovimento retorno = null;
            Sinacor.Servico.Bovespa.Movimento.BusinessLogic.ControleMovimentoOrdens ordens = new Sinacor.Servico.Bovespa.Movimento.BusinessLogic.ControleMovimentoOrdens();

            retorno = ordens.ObterInformacoesMovimento(new Movimento.BusinessEntity.DataMovimento());

            if (retorno.EstadoMovimento != Sinacor.Servico.Bovespa.Movimento.BusinessEntity.Enum.TipoMovimento.Aberto)
                throw new BusinessException(ERRO_MOVIMENTO_DIFERENTE_ABERTO);

        }

        /// <summary>
        /// Verifica a permissão de acesso para manipular os pré-boletos
        /// </summary>
        /// <param name="entityList"></param>
        private void VerificarPermissaoAcesso()
        {

            if (!AuthorizationContext.Current.CheckUserAccess("IORD", "ORD") && !AuthorizationContext.Current.CheckUserAccess("AORD", "ORD") && !AuthorizationContext.Current.CheckUserAccess("EORD", "ORD"))
                throw new BusinessException(ERRO_USUARIO_SEM_PREMISSAO_ACESSO);
        }

        /// <summary>
        /// Realiza o casamento dos pré-boletos de uma determinada ordem para uma
        /// determinada data de pregão
        /// </summary>
        /// <param name="parameter">BusinessEntity.Parameter.FiltroPreBoleto</param>
        public void CasarPreBoletos(BusinessEntity.Parameter.FiltroPreBoleto parameter)
        {
            BusinessLogic.ManutencaoOrdens blOrdem;
            BusinessEntity.Ordem beOrdem;
            ResourceAccess.Casamento raCasamento;
            BusinessEntity.Resultado beResultado;

            raCasamento = new Sinacor.Servico.Bovespa.ManutencaoOrdens.ResourceAccess.Casamento();

            if (parameter == null)
                throw new BusinessException(ERRO_OBJETO_CASAMENTO_NULO);

            this.VerificarPermissaoAcesso();
            this.ValidarEstadoMovimento();

            blOrdem = new ManutencaoOrdens();
            beOrdem = blOrdem.ObterOrdem(parameter.Ordem);

            if (beOrdem.IndicadorCasaOrdem.Value)
            {
                beResultado = raCasamento.CasarPreBoletos(parameter);
                if (!beResultado.Sucesso)
                {
                    if (beResultado.CodigoErro == -1)
                    {
                        throw new BusinessException(ERRO_CASAR_PREBOLETO);
                    }
                    else
                    {
                        this.TratarExcecoes(beResultado);
                    }
                }
            }
            else
            {
                throw new BusinessException(ERRO_NAO_PERMITE_CASAMENTO);
            }
        }
    }
}
